package com.qf.micrograss.grass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qf.api.dto.PointDTO;
import com.qf.api.point.PointFeignService;
import com.qf.common.core.common.R;
import com.qf.common.core.constant.CommonConstant;
import com.qf.common.core.entity.GrassInfo;
import com.qf.common.core.enums.PointTypeEnum;
import com.qf.common.core.page.PageParam;
import com.qf.common.core.page.PageVO;
import com.qf.common.core.utils.DateUtils;
import com.qf.common.core.utils.UserUtils;
import com.qf.common.minio.utils.MinioUtil;
import com.qf.common.redis.utils.RedisUtil;
import com.qf.micrograss.grass.mapper.GrassMapper;
import com.qf.micrograss.grass.param.GrassAddParam;
import com.qf.micrograss.grass.param.LikeNumParam;
import com.qf.micrograss.grass.service.GrassService;
import com.qf.micrograss.grass.vo.GrassVO;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * --- 缘分让我们相遇乱世以外 ---
 *
 * @author SJY
 * 2025/1/4
 */
@Service
public class GrassServiceImpl implements GrassService {

    @Resource
    private MinioUtil minioUtil;

    @Resource
    private PointFeignService pointFeignService;

    @Resource
    private GrassMapper grassMapper;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public String uploadImg(MultipartFile file) {
        String filename = file.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + filename.substring(filename.lastIndexOf("."));
        String path = null;
        try {
            path = minioUtil.upload(file.getInputStream(), filename);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return path;
    }

    // @Transactional(rollbackFor = Exception.class)
    // AT模式下,分布式事务的注解
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void addGrass(GrassAddParam param) {
        Integer uid = UserUtils.getUid();

        GrassInfo grassInfo = new GrassInfo();
        BeanUtils.copyProperties(param, grassInfo);
        // 将列表转为特定字符分割的字符串
        // String imgPath = param.getImgList()
        // String.join(",", param.getImgList());
        String imgPath = param.getImgList().stream().collect(Collectors.joining(","));
        grassInfo.setImgPath(imgPath);
        grassInfo.setUid(uid);
        grassMapper.insert(grassInfo);

        // 调用远程接口增加积分
        PointDTO pointDTO = new PointDTO();
        pointDTO.setPointType(PointTypeEnum.POINT_SIGN_PUBLISH.getType());
        //优化,远程送积分时,数据通过规则表查询,这些逻辑写在point模块中
        R r = pointFeignService.selPointRule(pointDTO);
        Object data = r.getData();
        Integer point = (Integer) data;
        pointDTO.setUid(uid);
        pointDTO.setPointType(PointTypeEnum.POINT_SIGN_PUBLISH.getType());
        pointDTO.setPoint(point);
        pointFeignService.remoteAddPoint(pointDTO);
        R ret = pointFeignService.remoteAddPoint(pointDTO);
        if (ret.getCode() != CommonConstant.SUCCESS) {
            throw new RuntimeException("增加积分失败");
        }
    }

    @Override
    public PageVO<GrassVO> grassPage(PageParam param) {
        Integer uid = UserUtils.getUid();
        //mybatisplus中的分页插件
        Page<GrassInfo> page = new Page<>(param.getPageNum(), param.getPageSize());
        grassMapper.selectPage(page,new LambdaQueryWrapper<GrassInfo>()
               .orderByDesc(GrassInfo::getCreateTime));

        String likeNumKey = String.format("likeNum:%s", DateUtils.formatLocalDate(LocalDate.now(), "yyyyMMdd"));
        List<GrassInfo> records = page.getRecords();
        List<GrassVO> voList = records.stream().map(item -> {
            GrassVO vo = new GrassVO();
            BeanUtils.copyProperties(item, vo);
            vo.setCover(item.getImgPath().split(",")[0]);
            // 查询点赞状态
            String likeKey = String.format("like:%s", item.getId());
            Integer v = redisUtil.getCacheMapValue(likeKey, uid.toString());
            vo.setLikeFlag(v == null? 0 : 1);
            // 查询当天的某个笔记的点赞数和数据库中的like_num加到一起后的结果
            Integer num = redisUtil.getCacheMapValue(likeNumKey, item.getId().toString());
            if (num !=null){
                vo.setLikeNum(vo.getLikeNum() + num);
            }
            return vo;
        }).collect(Collectors.toList());
        PageVO<GrassVO> pageVO = new PageVO<>();
        pageVO.setTotal(page.getTotal());
        pageVO.setDataList(voList);
        return pageVO;
    }

    @Override
    public void updateLikeNum(Integer id, Integer num) {
        grassMapper.updateLikeNum(id, num);
    }

    /**
     * 点赞数分批的批量更新
     */
    @Override
    public void updateLikeNumTask() {
        // 考虑到数据量可能比较大,不可能使用循环一条条数据更新
        // 方案: 分批批量更新
        // 定时任务,比如每天凌晨更新点赞数,那么就需要取昨天的点赞数
        String likeNumKey = String.format("likeNum:%s", DateUtils.formatLocalDate(LocalDate.now(), "yyyyMMdd"));
        Map<String, Integer> map = redisUtil.getCacheMap(likeNumKey);
        // 记录列表中元素的个数,达到五十就进行批量更新
        int count = 0;
        List<LikeNumParam> list = new ArrayList<>();
        // list.stream().forEach
        // list.forEach()
        for (String key : map.keySet()) {
            Integer likeNum = map.get(key);
            if (likeNum.equals(0)){
                continue;
            }else {
                LikeNumParam LikeNumparam = new LikeNumParam();
                LikeNumparam.setGrassId(Integer.parseInt(key));
                LikeNumparam.setLikeNum(likeNum);
                list.add(LikeNumparam);
                count++;
                if (count == 50) {
                    // 批量更新 sql中的case when then 语法
                    // 优化,使用redis的pipeline命令
                    grassMapper.updateLikeNumBatch(list);

                    count = 0;
                    list.clear();
                }
            }
        }
        if (count > 0){
            // 批量更新
            grassMapper.updateLikeNumBatch(list);
        }
        // 删除key

        // 借助CountDownLatch,当所有的线程异步执行完毕后,删除key
    }
}
